package ru.susu.algebra;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.List;

import ru.susu.algebra.chartable.constructor.AlternatingCharTableUtil;
import ru.susu.algebra.field.quadratic.ExpEvaluateOperation;
import ru.susu.algebra.field.quadratic.GeneralUnitFormatter;
import ru.susu.algebra.field.quadratic.QuadraticField;
import ru.susu.algebra.field.quadratic.QuadraticFieldGeneralForm;
import ru.susu.algebra.field.quadratic.QuadraticInteger;
import ru.susu.algebra.number.ClearSquaresOperation;
import ru.susu.algebra.pair.Pair;
import ru.susu.algebra.partition.Partition;
import ru.susu.algebra.partition.PartitionsCacheConstructor;
import ru.susu.algebra.partition.PartitionsFacade;
import ru.susu.algebra.partition.PartitionsFactory;
import ru.susu.algebra.partition.filter.CentralUnitPartitionFilter;
import ru.susu.algebra.partition.transformers.CentralUnitPartitionTransformer;
import ru.susu.algebra.ui.formatters.FactorizationFormatter;
import ru.susu.algebra.util.NumberUtilities;

/**
 * @author akargapolov
 * @since: 28.03.2009
 */
public class ExponentFounder
{
	public static void main(String[] args) throws Exception
	{
		NumberUtilities.isFullSquare(PartitionsFactory.createPartition(29, 9).getArrayRepresentation());
		PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("ExecuteResults/Exponent/exponents.txt")));

		for (int i = 2; i <= 25; i++)
		{
			System.out.println(i);

			List<Partition> partitions = new PartitionsCacheConstructor().getAscendingPartitions(i,
					new CentralUnitPartitionFilter());

			out.println("N = " + i);
			int j = 1;
			for (Partition partition : partitions)
			{
				out.print(j + ": ");
				partition.writeTo(out, partition.getPresentedNumber().toString().length() + 1);
				out.println();

				Partition trans = new CentralUnitPartitionTransformer().transformObject(partition);
				BigInteger degree = AlternatingCharTableUtil.calcAlternatingDegree(trans);
				String sDegree = degree.toString();

				out.println("Deg[x]: " + sDegree);
				BigInteger z = AlternatingCharTableUtil.calcZX(trans);
				out.println("Z[x]: " + z);

				QuadraticInteger qInteger = new QuadraticInteger(BigInteger.ONE, BigInteger.ONE, PartitionsFacade.getMainHooksProduct(trans));
				QuadraticFieldGeneralForm gUnit = new QuadraticField(qInteger).getGeneralUnit();
				out.println("Basic unit: " + gUnit);
				out.println("norm(unit): " + gUnit.norm());

				BigInteger exp = printExp(z, partition, out);

				if (i <= 6)
				{
					GeneralUnitFormatter gUnitFormatter = new GeneralUnitFormatter(new FactorizationFormatter());
					QuadraticFieldGeneralForm gUnitExpPow = (QuadraticFieldGeneralForm)gUnit.pow(exp);
					out.println("unit^exp: " + gUnitExpPow);// + " = " + gUnitFormatter.format(gUnitExpPow));
					out.println("norm(unit^exp): " + gUnitExpPow.norm());
				}

				j++;

			}

			out.println();
		}

		out.close();
	}

	/**
	 * См стр 66 и 112 в диссертации Алеева
	 * @param z
	 * @param partition
	 * @param out
	 */
	private static BigInteger printExp(BigInteger z, Partition partition, PrintWriter out)
	{
		ExpEvaluateOperation expOp = new ExpEvaluateOperation();
		FactorizationFormatter factorizationFormetter = new FactorizationFormatter();
		BigInteger k = BigInteger.valueOf(1);
		for (Integer i : partition.getArrayRepresentation())
			k = k.multiply(BigInteger.valueOf(i));
		k = new ClearSquaresOperation().performOperation(k);

		StringBuffer buf = new StringBuffer();
		BigInteger result = BigInteger.ONE;

		for (Pair<Integer, Integer> pair : NumberUtilities.factorization(z))
		{
			BigInteger p = BigInteger.valueOf(pair.getKey());
			BigInteger exp = expOp.performOperation(z, p, k);
			buf.append("exp(p = " + p + ") = " + exp + " = " + factorizationFormetter.format(exp) + "\n");
			BigInteger gcd = result.gcd(exp);
			result = result.divide(gcd).multiply(exp);
		}

		buf.insert(0, "Exp(Z = " + z + ", K = " + k + ") = " + result + " = " + factorizationFormetter.format(result) + "\n");

		out.println(buf.toString());

		return result;
	}
}
